/*
 * -----------------------------------
 * Singly linked list implementation
 * -----------------------------------
 * Copyright (C) 2021 AlexCr4ckPentest
 * -----------------------------------
*/



#pragma once

#ifndef __C_LINKED_LISTS__FORWARD_LIST_H
#define __C_LINKED_LISTS__FORWARD_LIST_H

#include <stddef.h>

struct forward_list_node;
typedef void(*forward_list_node_destructor_t)(struct forward_list_node* const);

struct forward_list
{
    struct forward_list_node* __head;
    struct forward_list_node* __tail;
    size_t __size;
    forward_list_node_destructor_t __node_destructor;
};

typedef struct forward_list_node** forward_list_iterator_t;



/*
 * forward_list_node interface
*/

struct forward_list_node* forward_list_node__construct(void* data, struct forward_list_node* next);



/*
 * forward_list interface
*/

void forward_list__construct(struct forward_list* list);
void forward_list__destruct(struct forward_list* const list);
void forward_list__copy(struct forward_list* dst, struct forward_list* const src);
void forward_list__swap(struct forward_list* lhs, struct forward_list* rhs);
void forward_list__remove_front(struct forward_list* list);
void forward_list__remove_back(struct forward_list* list);
void forward_list__clear(struct forward_list* const list);
void forward_list__add_front(struct forward_list* list, void* data);
void forward_list__add_back(struct forward_list* list, void* data);
void forward_list__merge_back(struct forward_list* dst, struct forward_list* const src);
void forward_list__merge_front(struct forward_list* dst, struct forward_list* const src);
void forward_list__remove_at(struct forward_list* list, forward_list_iterator_t pos);
void forward_list__remove_after(struct forward_list* list, forward_list_iterator_t pos);
void forward_list__insert_at(struct forward_list* list, void* data, forward_list_iterator_t pos);
void forward_list__insert_after(struct forward_list* list, void* data, forward_list_iterator_t pos);
void forward_list__merge_at(struct forward_list* dst, struct forward_list* const src, forward_list_iterator_t pos);
void forward_list__merge_after(struct forward_list* dst, struct forward_list* const src, forward_list_iterator_t pos);



/*
 * forward_list getters and setters
*/

size_t forward_list__size(struct forward_list* const list);
int forward_list__is_empty(struct forward_list* const list);
void* forward_list__get_at(struct forward_list* const list, size_t index);
void* forward_list__get_back(struct forward_list* const list);
void* forward_list__get_front(struct forward_list* const list);
const void* forward_list__get_at_const(struct forward_list* const list, size_t index);
const void* forward_list__get_front_const(struct forward_list* const list);
const void* forward_list__get_back_const(struct forward_list* const list);
void** forward_list__get_at_addr(struct forward_list* const list, size_t index);
void** forward_list__get_front_addr(struct forward_list* const list);
void** forward_list__get_back_addr(struct forward_list* const list);
const void** forward_list__get_at_addr_const(struct forward_list* const list, size_t index);
const void** forward_list__get_front_addr_const(struct forward_list* const list);
const void** forward_list__get_back_addr_const(struct forward_list* const list);
void forward_list__set_node_destructor(struct forward_list* list, forward_list_node_destructor_t node_destructor);
forward_list_iterator_t forward_list__begin(struct forward_list* const list);
forward_list_iterator_t forward_list__end(struct forward_list* const list);
forward_list_iterator_t __forward_list__find_impl(struct forward_list* const list, void* data, size_t type_size);
forward_list_iterator_t forward_list__find_if(struct forward_list* const list, int(*predicate)(void* data));

#define forward_list__find(ptr, data, type) \
    __forward_list__find_impl(ptr, data, sizeof(type))



/*
 * forward_list iterator functions
*/

struct forward_list_node* __forward_list_iterator__get_ptr(forward_list_iterator_t iter);
forward_list_iterator_t forward_list_iterator__next(forward_list_iterator_t* iter);
forward_list_iterator_t forward_list_iterator__advance(forward_list_iterator_t* iter, size_t n);
void* forward_list_iterator__extract_data(forward_list_iterator_t iter);
void** forward_list_iterator__extract_data_addr(forward_list_iterator_t iter);

#endif // __C_LINKED_LISTS__FORWARD_LIST_H
